package cn.likole.oj.module;


import cn.likole.oj.bean.*;
import cn.likole.oj.service.AchievementService;
import cn.likole.oj.service.MoneyService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.dao.util.cri.Static;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.annotation.*;
import org.nutz.mvc.filter.CheckSession;
import org.nutz.plugins.apidoc.annotation.Api;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.util.Date;
import java.util.List;

import static cn.likole.oj.constant.Constant.DATA_PATH;

@IocBean
@At("/judge")
@Filters(@By(type = CheckSession.class, args = {"http_judge", "/blank"}))
@Ok("json:full")
@Api(name = "判题模块",description = "跟判题机进行对接所使用到的借口")
public class JudgeModule {

    @Inject
    protected Dao dao;

    @Inject
    private AchievementService achievementService;

    @Inject
    private MoneyService moneyService;

    @At
    @Filters
    public int checkLogin(HttpSession session){
        if(session.getAttribute("http_judge")!=null)
            return 1;
        return 0;
    }

    @At
    @POST
    @Filters
    public void login(HttpSession session,@Param("user_id")String uid,@Param("password")String pswd){
        NutMap re=new NutMap();
        if("judge".equals(uid)&&"judgee".equals(pswd)) session.setAttribute("http_judge","1");
    }

    @At
    public void updateSolution(HttpServletRequest req, @Param("sid")int id, @Param("result")int result, @Param("time")int time, @Param("memory")int memory, @Param("sim")int sim, @Param("simid")int simid){
        Solution solution=dao.fetch(Solution.class,id);
        solution.setResult(result);
        solution.setTime(time);
        solution.setMemory(memory);
        solution.setJudger(req.getRemoteAddr());
        solution.setJudgeTime(new Date());
//        moneyService.solved(solution);//增加金币
        dao.update(solution);
        if(sim!=0){
            Sim tsim=new Sim();
            tsim.setSim(sim);
            tsim.setSolutionId(id);
            tsim.setTargetId(simid);
            dao.insertOrUpdate(tsim);
        }
//        achievementService.onError(solution);//错误时的参数
    }

    @At
    public void addceinfo(@Param("sid")int id,@Param("ceinfo")String ceinfo){
        dao.delete(CompileInfo.class,id);
        CompileInfo compileInfo=new CompileInfo();
        compileInfo.setSolutionId(id);
        compileInfo.setError(ceinfo);
        dao.insert(compileInfo);
    }

    @At
    public void addreinfo(@Param("sid")int id,@Param("reinfo")String reinfo){
        dao.delete(RuntimeInfo.class,id);
        RuntimeInfo runtimeInfo=new RuntimeInfo();
        runtimeInfo.setSolutionId(id);
        runtimeInfo.setError(reinfo);
        dao.insert(runtimeInfo);
    }

    @At
    public void updateUser(@Param("user_id")int id){
        User user=dao.fetch(User.class,id);
        int solved=dao.func(Solution.class,"count","distinct problemId", Cnd.where("userId","=",id).and("result","=",4));
        int submit=dao.func(Solution.class,"count", "*",Cnd.where("userId","=",id).and("problemId",">",0));
        user.setSolved(solved);
        user.setSubmit(submit);
        dao.update(user);
    }

    @At
    public void updateProblem(@Param("pid")int pid){
        Problem problem=dao.fetch(Problem.class,Cnd.where("problemId","=",pid));
        int accepted=dao.func(Solution.class,"count","*",Cnd.where("problemId","=",pid).and("result","=",4));
        int submit=dao.func(Solution.class,"count","*",Cnd.where("problemId","=",pid));
        problem.setAccepted(accepted);
        problem.setSubmit(submit);
        dao.update(problem);
    }

    @At
    @Ok("raw")
    public String getSolutioninfo(@Param("sid")int id){
        Solution solution=dao.fetch(Solution.class, id);
        return solution.toString1();
    }

    @At
    @Ok("raw")
    public String getSolution(@Param("sid")int id){
        return dao.fetch(SourceCode.class,id).getSource();
    }

    @At
    @Ok("raw")
    public String getCustominput(@Param("sid")int id){
        return dao.fetch(CustomInput.class,id).getText();
    }



    @At
    @Ok("raw")
    public String getProbleminfo(@Param("pid")int id){
        Problem problem=dao.fetch(Problem.class,id);
        return problem.toString1();
    }

    @At
    @Ok("raw")
    public String getTestdatalist(@Param("pid")int id){
        String res="";
        File file=new File(Thread.currentThread().getContextClassLoader().getResource("/").getPath()+DATA_PATH+id);
        File[] filelist=file.listFiles();
        for(File file1:filelist){
            if(file1.isFile())
                res+=file1.getName()+"\n";
        }
        return res;
    }

    @At
    @Ok("raw")
    public String getTestdata(@Param("filename") String filename){
        File file=new File(Thread.currentThread().getContextClassLoader().getResource("/").getPath()+DATA_PATH+filename);
        String data="";
        if(file!=null&&file.canRead()){
            try {
                Reader in=new FileReader(file);
                StringWriter out=new StringWriter();
                int c=-1;
                while((c=in.read())!=-1)
                    out.write(c);
                data=out.toString();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                return "文件丢失";
            } catch (IOException e) {
                e.printStackTrace();
                return "文件读写错误";
            }

        }
        return data;
    }

    @At
    @Ok("raw")
    public String getTestdatadate(@Param("filename")String filename){
        File file= new File(Thread.currentThread().getContextClassLoader().getResource("/").getPath()+DATA_PATH+filename);
        return file.lastModified()/1000+"";
    }

    @At
    @Ok("raw")
    public String checkout(@Param("sid")int id,@Param("result")int result){
        SqlExpressionGroup e1=Cnd.exps("result","<",4).and(new Static("NOW()-judgeTime>60"));
        SqlExpressionGroup e2=Cnd.exps("result","<",2).or(e1);
        List<Solution> solutions=dao.query(Solution.class,Cnd.where("solutionId","=",id).and(e2));
        if(solutions.get(0)!=null)
        {
            Solution solution=solutions.get(0);
            solution.setResult(result);
            solution.setTime(0);
            solution.setMemory(0);
            solution.setJudgeTime(new Date());
            dao.update(solution);
            return "1";
        }
        return "0";
    }

    @At
    @Ok("raw")
    public String getpending(@Param("oj_lang_set")String oj_lang_set,@Param("max_running")int max_runnning){
//        String[] langs=oj_lang_set.split(",");
//        oj_lang_set="";
//        for (String lang:langs) {
//            int tmp=Integer.parseInt(lang);
//            if(oj_lang_set!="")oj_lang_set+=",";
//            oj_lang_set+=tmp;
//        }
        StringBuilder res=new StringBuilder();
        Sql sql= Sqls.create("SELECT solutionId FROM solution WHERE language in (@oj_lang_set) and (result<2 or (result<4 and NOW()-judgeTime>60)) ORDER BY result ASC,solutionId ASC limit @max_running");
        sql.params().set("oj_lang_set",oj_lang_set.split(",")).set("max_running",max_runnning);
        sql.setCallback(Sqls.callback.ints());
        dao.execute(sql);
        List<Integer> list=sql.getList(Integer.class);
        for (int solution_id:list) {
            res.append(solution_id);
            res.append("\n");
        }
        return res.toString();
    }

}
